package easy.trace.agent.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

/**
 * @author easy
 * @data 23/05/2018.
 */
public class ConfigurationResourcesResolver {

    public final static String DEFAULT_LOCAL_LOG4J_FILE = "trace.properties";
    public final static String DEFAULT_APPLICATION_LOG4J_FILE = "log4j.properties";
    public final static String DEFAULT_EXCLUDE_APPLICATION_LOG4J_PATH = ".jar";
    public final static String DEFAULT_INCLUDE_APPLICATION_LOG4J_PATH = "classes";

    /**
     * 配置文件中存在trace 配置
     *
     * @param oldConfig
     * @param traceConfigs
     * @return
     */
    public static boolean existLine(String oldConfig, Set<String> traceConfigs) {
        if (oldConfig == null || oldConfig.trim().length() == 0) {
            return false;
        }
        if (traceConfigs.contains(oldConfig.trim())) {
            return true;
        }
        return false;
    }

    /**
     * 获取文件信息
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public static List<String> loadConfig(Path filePath) throws IOException, URISyntaxException {
        if (filePath != null && Files.exists(filePath)) {
            return Files.readAllLines(filePath);
        }
        return null;
    }


    /**
     * 获取log4j文件绝对路径
     *
     * @param file
     * @return
     */
    public static URL getLog4jFileAbsolutePath(String file) {
        List<URL> resources = getResources(file);
        if (resources != null && resources.size() > 0) {
            return resources
                    .stream()
                    .filter(url -> !url.getPath().contains(DEFAULT_EXCLUDE_APPLICATION_LOG4J_PATH))
                    .filter(url -> url.getPath().contains(DEFAULT_INCLUDE_APPLICATION_LOG4J_PATH))
                    .findFirst()
                    .orElseGet(null);
        }
        return null;
    }


    /**
     * 获取文件绝对路径
     *
     * @param file
     * @return
     */
    public static URL getFileAbsolutePath(String file) {
        List<URL> resources = getResources(file);
        if (resources != null && resources.size() > 0) {
            return resources.stream()
                    .filter(resource -> resource.getPath().contains(DEFAULT_EXCLUDE_APPLICATION_LOG4J_PATH))
                    .findFirst()
                    .orElseGet(null);
        }
        return null;
    }

    /**
     * jar 包内配置文件
     *
     * @return
     * @throws IOException
     */
    public static List<String> loadLocalConfig() throws IOException, URISyntaxException {
        URL url = getFileAbsolutePath(DEFAULT_LOCAL_LOG4J_FILE);
        if (url == null) {
            return null;
        }
        return readConfigLines(url.openStream());
    }

    private static List<String> readConfigLines(InputStream input) throws IOException {
        List<String> configs = new ArrayList<>();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            String configLine;
            while ((configLine = reader.readLine()) != null) {
                if (configLine.trim().length() == 0) {
                    continue;
                }
                configs.add(configLine);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            input.close();
        }
        return configs;
    }

    /**
     * class 文件目录下配置文件
     *
     * @return
     * @throws IOException
     */
    public static List<String> loadApplicationConfig() throws IOException, URISyntaxException {
        URL url = getLog4jFileAbsolutePath(DEFAULT_APPLICATION_LOG4J_FILE);
        if (url == null) {
            return null;
        }
        Path filePath = Paths.get(url.getPath());
        return loadConfig(filePath);
    }

    private static List<URL> getResources(String resource) {
        List<URL> cfgUrlPaths = new ArrayList<>();
        Enumeration<URL> urls;
        try {
            urls = getDefaultClassLoader().getResources(resource);

            while (urls.hasMoreElements()) {
                URL pluginUrl = urls.nextElement();
                cfgUrlPaths.add(pluginUrl);
                System.out.println("find resources define in " + pluginUrl);
            }

            return cfgUrlPaths;
        } catch (IOException e) {
            System.out.println("read resources failure." + e);
        }
        return null;
    }

    private static ClassLoader getDefaultClassLoader() {
        ClassLoader cl = null;
        try {
            cl = Thread.currentThread().getContextClassLoader();
        } catch (Throwable ex) {
            // Cannot access thread context ClassLoader - falling back to system class loader...
        }
        if (cl == null) {
            // No thread context class loader -> use class loader of this class.
            cl = PluginResourcesResolver.class.getClassLoader();
        }
        return cl;
    }
}
